package com.bolt.report.engine.query;

import com.bolt.common.BoltConstants;
import com.bolt.common.bean.BeanUtil;
import com.bolt.common.convert.Convert;
import com.bolt.convention.exception.ServiceException;
import com.bolt.report.definition.DataSetDefinition;
import com.bolt.report.definition.JdbcDataSourceDefinition;
import com.bolt.report.engine.BRDataSource;
import com.bolt.report.engine.CollectionDataSource;
import com.bolt.report.engine.ObjectFactory;
import com.bolt.report.exception.ReportException;
import com.bolt.support.spring.jpa.query.PropertiesSqlParameterSource;
import com.bolt.support.sqlconfig.base.SqlStatement;
import com.bolt.support.sqlconfig.base.SqlText;
import com.bolt.support.sqlconfig.dialect.PagingDialect;
import com.bolt.support.sqlconfig.dialect.PagingDialectFactory;
import net.sf.jasperreports.engine.JRParameter;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
import org.springframework.jdbc.datasource.SingleConnectionDataSource;
import org.springframework.jdbc.support.JdbcUtils;

import java.sql.Connection;
import java.util.List;
import java.util.Map;

public class JdbcQueryExecute implements QueryExecute {

    private final Log logger = LogFactory.getLog(getClass());

    private DataSetDefinition dataSetDefinition;

    private SqlStatement queryStatement;

    private Map<String, Object> parameters;


    public JdbcQueryExecute(DataSetDefinition dataSetDefinition, Map<String, Object> parameters) {
        this.dataSetDefinition = dataSetDefinition;
        this.parameters = parameters;
        parseQuery();
    }

    protected void parseQuery() {

        queryStatement = ObjectFactory.parseSqlText(this.dataSetDefinition.getQuerySql());
    }

    public BRDataSource createBRDataSource() {
        Connection connection = (Connection) parameters.get(JRParameter.REPORT_CONNECTION);
        try {
            SqlText sqlText = queryStatement.getSqlText(parameters);
            JdbcDataSourceDefinition dataSourceDefinition = dataSetDefinition.getJdbcConnectionDef();
            if (connection != null) {
                SingleConnectionDataSource datasource = new SingleConnectionDataSource(connection, true);
                String querySql;
                if (dataSetDefinition.isPage()) {
                    PagingDialect pagingDialect = PagingDialectFactory.getDialect(dataSourceDefinition.getDbUrl());
                    Integer[] pageable = getPageable();
                    querySql = pagingDialect.getLimitString(sqlText.getSql(), pageable[0], pageable[1]);
                } else {
                    querySql = sqlText.getSql();
                }
                NamedParameterJdbcTemplate query = new NamedParameterJdbcTemplate(datasource);
                SqlParameterSource parameterSource = new PropertiesSqlParameterSource(sqlText.getParameterValues());
                List<Map<String, Object>> data = query.queryForList(querySql, parameterSource);

                return new CollectionDataSource(data);
            } else {
                throw new ReportException("The supplied java.sql.Connection object is null");
            }
        } catch (Exception ex) {
            logger.error(ex);

            throw new ServiceException(ex);
        } finally {
            JdbcUtils.closeConnection(connection);
        }
    }




    private Integer[] getPageable() {
        Integer[] pageable = new Integer[2];
        Object pageNumber = BeanUtil.getFieldValue(parameters, BoltConstants.PAGE_CURRENT_KEY);
        Integer number = Convert.toInt(pageNumber, 0);
        pageable[0] = number;
        Object pageSize = BeanUtil.getFieldValue(parameters, BoltConstants.PAGE_SIZE);
        Integer size = Convert.toInt(pageSize, 10);
        pageable[1] = size;
        return pageable;
    }

    @Override
    public List<?> queryData() {
       return  ((CollectionDataSource)createBRDataSource()).getData();
    }
}